package org.jsola.contract.service.impl;

import org.jsola.cache.ICache;
import org.jsola.contract.common.CacheKeyKit;
import org.jsola.contract.common.ExampleKit;
import org.jsola.contract.constant.ContractConstants;
import org.jsola.contract.dao.IContractConfigSiteDAO;
import org.jsola.contract.dto.ContractConfigSiteAddDTO;
import org.jsola.contract.dto.ContractConfigSiteUpdateDTO;
import org.jsola.contract.dto.ContractPayLogAddDTO;
import org.jsola.contract.entity.ContractConfigSiteDO;
import org.jsola.contract.query.ContractConfigSiteQuery;
import org.jsola.contract.service.IContractConfigSiteService;
import org.jsola.contract.service.IContractPayLogService;
import org.jsola.contract.vo.ContractConfigSiteListVO;
import org.jsola.contract.vo.ContractConfigSiteVO;
import org.jsola.contract.vo.ContractMarginVO;
import org.jsola.core.Page;
import org.jsola.core.entity.BaseDO;
import org.jsola.exception.ParamException;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 租户电子合同配置
 *
 * @author JanusMix
 */
@Service("contractContractConfigSiteServiceImpl")
public class ContractConfigSiteServiceImpl implements IContractConfigSiteService {

    @Autowired
    private IContractConfigSiteDAO contractConfigSiteDAO;
    @Autowired
    private IContractPayLogService contractPayLogService;
    @Autowired
    private ICache cache;

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public ContractConfigSiteVO save(ContractConfigSiteAddDTO contractConfigSiteAddDTO, TokenUser tokenUser) {
        // 转DO
        ContractConfigSiteDO contractConfigSiteDO = contractConfigSiteAddDTO.to(ContractConfigSiteDO.class);
        ParamException.isFalse(this.selectCount(new ContractConfigSiteQuery(), tokenUser.getSiteId()) > 0, "租户已经有合同配置，请勿重复创建");
        // 保存
        contractConfigSiteDO = save(contractConfigSiteDO, tokenUser.getSiteId(), tokenUser.getUserId());
        setCache(contractConfigSiteDO, tokenUser);
        return contractConfigSiteDO.to(ContractConfigSiteVO.class);
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int update(ContractConfigSiteUpdateDTO contractConfigSiteUpdateDTO, TokenUser tokenUser) {
        //转DO
        ContractConfigSiteDO contractConfigSiteDO = contractConfigSiteUpdateDTO.to(ContractConfigSiteDO.class);
        //根据主键更新，只更新非null值
        int updateByIdSelective = updateByIdSelective(contractConfigSiteDO, tokenUser.getSiteId(), tokenUser.getUserId());
        if (updateByIdSelective < 1) {
            return updateByIdSelective;
        }
        setCache(contractConfigSiteDO, tokenUser);
        return updateByIdSelective;
    }

    /**
     * 设置缓存
     *
     * @param contractConfigSiteDO 合同配置
     * @param tokenUser            当前用户
     */
    private void setCache(ContractConfigSiteDO contractConfigSiteDO, TokenUser tokenUser) {
        // 修改缓存中的值
        String contractMargin = CacheKeyKit.getContractMargin(tokenUser.getSiteId());
        ContractMarginVO contractMarginVO = contractConfigSiteDO.to(ContractMarginVO.class);
        contractMarginVO.setDatabaseModified(new Date());
        cache.set(contractMargin, contractMarginVO);
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, Long... contractConfigSiteIds) {
        // 删除
        int deleteByIds = deleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) contractConfigSiteIds);
        // 删除缓存
        String contractMargin = CacheKeyKit.getContractMargin(tokenUser.getSiteId());
        cache.delKey(contractMargin);
        return deleteByIds;
    }


    @Override
    public ContractConfigSiteVO selectById(Long contractConfigSiteId, String siteId) {
        ContractConfigSiteDO contractConfigSiteDO = selectDOById(contractConfigSiteId, siteId);
        if (contractConfigSiteDO == null) {
            return null;
        }
        return contractConfigSiteDO.to(ContractConfigSiteVO.class);
    }

    @Override
    public List<ContractConfigSiteDO> selectByIds(List<Long> contractConfigSiteIds) {
        if (CollectionUtils.isEmpty(contractConfigSiteIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(ContractConfigSiteDO.class);
        example.and()
                .andIn("id", contractConfigSiteIds);
        return contractConfigSiteDAO.selectByExample(example);
    }

    @Override
    public List<ContractConfigSiteListVO> select(ContractConfigSiteQuery contractConfigSiteQuery, String siteId) {
        List<ContractConfigSiteDO> contractConfigSiteDOList = selectDO(contractConfigSiteQuery, siteId);
        if (CollectionUtils.isEmpty(contractConfigSiteDOList)) {
            return contractConfigSiteDOList == null ? null : new ArrayList<>();
        }
        return contractConfigSiteDOList.stream()
                .map(contractConfigSiteDO -> contractConfigSiteDO.to(ContractConfigSiteListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(ContractConfigSiteQuery contractConfigSiteQuery, String siteId) {
        Example example = buildExample(contractConfigSiteQuery, siteId);
        return contractConfigSiteDAO.selectCountByExample(example);
    }

    @Override
    public Page<ContractConfigSiteListVO> selectPage(ContractConfigSiteQuery contractConfigSiteQuery, String siteId) {
        Example example = buildExample(contractConfigSiteQuery, siteId);
        Page<ContractConfigSiteDO> page = contractConfigSiteDAO.selectPageByExample(example,
                contractConfigSiteQuery.getPageNo(),
                contractConfigSiteQuery.getPageSize());

        return page.to(ContractConfigSiteListVO.class);
    }

    @Override
    public ContractConfigSiteDO selectDOById(Long contractConfigSiteId, String siteId) {
        return listById(contractConfigSiteId, siteId);
    }

    @Override
    public List<ContractConfigSiteDO> selectDO(ContractConfigSiteQuery contractConfigSiteQuery, String siteId) {
        Example example = buildExample(contractConfigSiteQuery, siteId);
        return contractConfigSiteDAO.selectByExample(example);
    }

    @Override
    public Page<ContractConfigSiteDO> selectAllPage(ContractConfigSiteQuery contractConfigSiteQuery) {
        Example example = new Example(ContractConfigSiteDO.class);
        Page<ContractConfigSiteDO> page = contractConfigSiteDAO.selectPageByExample(example,
                contractConfigSiteQuery.getPageNo(),
                contractConfigSiteQuery.getPageSize());
        List<ContractConfigSiteDO> contractConfigSiteList = page.getEntities();
        if (!CollectionUtils.isEmpty(contractConfigSiteList)) {
            // 先读取缓存的信息
            for (ContractConfigSiteDO contractConfigSiteDO : contractConfigSiteList) {
                String contractMargin = CacheKeyKit.getContractMargin(contractConfigSiteDO.getSiteId());
                ContractMarginVO contractMarginVO = cache.get(contractMargin);
                if (contractMarginVO != null) {
                    contractConfigSiteDO.setTotalCount(contractMarginVO.getTotalCount());
                    contractConfigSiteDO.setQuotaRemain(contractMarginVO.getQuotaRemain());
                }
            }
        }
        return page;
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public void enableContractConfig(Long configId, Boolean enable, TokenUser tokenUser) {
        // 查询缓存中的余量 若存在使用缓存的
        String contractMargin = CacheKeyKit.getContractMargin(tokenUser.getSiteId());
        ContractConfigSiteDO contractConfigSiteDO = selectDOById(configId, tokenUser.getSiteId());
        if (contractConfigSiteDO == null) {
            // 数据库配置信息不存在 清除缓存并报错
            cache.delKey(contractMargin);
            throw new ParamException("配置不存在");
        }
        contractConfigSiteDO.setEnable(enable);
        ContractMarginVO contractMarginVO = cache.get(contractMargin);
        // 关闭时放入缓存中的余量
        if (contractMarginVO != null) {
            contractConfigSiteDO.setQuotaRemain(contractMarginVO.getQuotaRemain());
        }
        // 开启或关闭时 更新缓存
        setCache(contractConfigSiteDO, tokenUser);
        updateByIdSelective(contractConfigSiteDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public void payContractConfigQuota(Long configId, Integer quota, TokenUser tokenUser) {
        ContractConfigSiteDO contractConfigSiteDO = this.selectDOById(configId, tokenUser.getSiteId());
        ParamException.notNull(contractConfigSiteDO, "配置不存在");
        Integer quotaRemain = contractConfigSiteDO.getQuotaRemain();
        // 查询缓存中的余量 若存在使用缓存的
        String contractMargin = CacheKeyKit.getContractMargin(tokenUser.getSiteId());
        ContractMarginVO contractMarginVO = cache.get(contractMargin);
        if (contractMarginVO != null) {
            quotaRemain = contractMarginVO.getQuotaRemain();
        }
        contractConfigSiteDO.setQuotaRemain(quotaRemain + quota);
        //修改剩余额度
        updateByIdSelective(contractConfigSiteDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 修改缓存数量
        setCache(contractConfigSiteDO, tokenUser);
        ContractPayLogAddDTO contractPayLogAddDTO = new ContractPayLogAddDTO();
        contractPayLogAddDTO.setQuotaPay(quota);
        //保存充值记录
        contractPayLogService.save(contractPayLogAddDTO, tokenUser);
    }

    @Override
    public ContractConfigSiteDO selectBySiteId(String siteId) {
        if (siteId == null) {
            return null;
        }
        Example example = new Example(ContractConfigSiteDO.class);
        example.and()
                .andEqualTo("siteId", siteId);
        ContractConfigSiteDO contractConfigSiteDO = contractConfigSiteDAO.selectOneByExample(example);
        // 缓存中有的 使用缓存中的数据
        String contractMargin = CacheKeyKit.getContractMargin(siteId);
        ContractMarginVO contractMarginVO = cache.get(contractMargin);
        if (contractConfigSiteDO != null && contractMarginVO != null) {
            contractConfigSiteDO.setQuotaRemain(contractMarginVO.getQuotaRemain());
        }
        return contractConfigSiteDO;
    }


    /**
     * 根据查询参数，构建example
     *
     * @param contractConfigSiteQuery 查询参数
     * @param siteId                  所属站点id
     * @return example
     */
    private Example buildExample(ContractConfigSiteQuery contractConfigSiteQuery, String siteId) {
        Example example = new Example(ContractConfigSiteDO.class);
        example.and()
                .andEqualTo("siteId", siteId);
        if (contractConfigSiteQuery.getEnableCheckFace() != null) {
            example.and().andEqualTo("enableCheckFace", contractConfigSiteQuery.getEnableCheckFace());
        }
        if (contractConfigSiteQuery.getEnableCheckSms() != null) {
            example.and().andEqualTo("enableCheckSms", contractConfigSiteQuery.getEnableCheckSms());
        }
        // 排序
        ExampleKit.setExampleOrder(example, contractConfigSiteQuery.getOrders());
        return example;
    }
}




